package com.aliyun.messagemgt.application.service.sms.impl;

import com.aliyun.messagemgt.common.annotation.PagingAnnotation;
import com.aliyun.messagemgt.application.service.sms.SmsQuotaService;
import com.aliyun.messagemgt.util.SmsQuotaDateUtils;
import com.aliyun.messagemgt.common.constants.SmsQuotaConstant;
import com.aliyun.messagemgt.domain.repository.SmsQuotaMonitorRepository;
import com.aliyun.messagemgt.domain.repository.SmsQuotaRenewRepository;
import com.aliyun.messagemgt.domain.repository.SmsQuotaRepository;
import com.aliyun.messagemgt.domain.repository.SmsQuotaUsedRepository;
import com.aliyun.messagemgt.dto.SmsQuota;
import com.aliyun.messagemgt.dto.SmsQuotaMonitor;
import com.aliyun.messagemgt.dto.SmsQuotaRenew;
import com.aliyun.messagemgt.dto.SmsQuotaUsed;
import com.aliyun.messagemgt.dto.vo.DepVo;
import com.aliyun.messagemgt.dto.vo.SmsQuotaRequestVO;
import com.aliyun.messagemgt.dto.vo.SmsQuotaResponseVO;
import com.github.pagehelper.PageInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 短信配额实现类
 *
 * @author byp
 * @date 2020/7/13
 */
@Service
public class SmsQuotaServiceImpl implements SmsQuotaService {

    private final Logger logger = LoggerFactory.getLogger(SmsQuotaServiceImpl.class);
    @Autowired
    private SmsQuotaRepository smsQuotaRepository;

    @Autowired
    private SmsQuotaRenewRepository smsQuotaRenewRepository;

    @Autowired
    private SmsQuotaUsedRepository smsQuotaUsedRepository;

    @Autowired
    private SmsQuotaMonitorRepository smsQuotaMonitorRepository;

    @Override
    public Integer smsQuotaAdd(SmsQuotaRequestVO smsQuotaRequestVO) {
        if (smsQuotaRequestVO.getQuotaPackageNum() != null && smsQuotaRequestVO.getQuotaPackageNum() > SmsQuotaConstant.MAX_PACKAGE_NUM) {
            throw new RuntimeException("短信配额包数量最多为10个");
        }
        SmsQuota smsQuota = smsQuotaRequestVO.convertToSmsQuota();
        logger.info("添加短信配额转换入参后smsQuota：{}", smsQuota);
        //判断立即生效。需要去比较配额和已使用量
        if (SmsQuotaConstant.EFFECTIVE_TYPE_NOW.equals(smsQuota.getEffectiveType())) {
            boolean compareResult = compareAddAndUsed(smsQuota);
            if (!compareResult) {
                throw new RuntimeException("当前配置额度小于或等于使用额度，请重新配置");
            }
        }
        //生效的配额
        SmsQuota effectiveQuota = smsQuotaRepository.queryQuotaByMsgSourceIdAndStatus(smsQuota.getMsgSourceId(), SmsQuotaConstant.EFFECTIVE_STATUS_SHENGXIAO);
        if (effectiveQuota == null) {
            throw new RuntimeException("无法找到该消息源的有效配额的数据");
        }
        //未生效的配额
        SmsQuota unEffectiveQuota = smsQuotaRepository.queryQuotaByMsgSourceIdAndStatus(smsQuota.getMsgSourceId(), SmsQuotaConstant.EFFECTIVE_STATUS_WEISHENGXIAO);
        //2020年7月27日16:23与PD任亮沟通：立即生效会覆盖未生效的配置,无论是月->年 还是年->月 还是同一纬度下的配置
        if (unEffectiveQuota != null) {
            unEffectiveQuota.setEffectiveStatus(SmsQuotaConstant.EFFECTIVE_STATUS_SHIXIAO);
            unEffectiveQuota.setEffectiveEndTime(new Date());
            unEffectiveQuota.setUpdateUserName(smsQuotaRequestVO.getUserName());
            unEffectiveQuota.setUpdateUserCode(smsQuotaRequestVO.getUserId());
            smsQuotaRepository.update(unEffectiveQuota);
        }
        //根据2020年7月16日确定的需求
        if (SmsQuotaConstant.EFFECTIVE_TYPE_NOW.equals(smsQuota.getEffectiveType())) {
            logger.info("添加短信配额立即生效");
            //1.1立即生效：肯定有一条生效的数据，把生效的这条数据设置为失效,然后查询这条新数据。
            effectiveQuota.setEffectiveStatus(SmsQuotaConstant.EFFECTIVE_STATUS_SHIXIAO);
            effectiveQuota.setEffectiveEndTime(new Date());
            //1.2立即生效的数据,设置立即生效日期，修改人等数据
            smsQuota.setEffectiveStatus(SmsQuotaConstant.EFFECTIVE_STATUS_SHENGXIAO);
            smsQuota.setEffectiveBeginTime(new Date());
            //1.3 判断该消息源有没有未生效数据。
            //1.4 判断是否有监控信息。有的话保存到monitor表中
            this.executeMonitorInfo(smsQuota, effectiveQuota);
            //1.5 处理续订信息（年转月）
            this.executeRenewInfo(smsQuota, effectiveQuota);
        } else {
            logger.info("添加短信配额次月/年生效");
            //2.次月/年生效：未生效的数据最多一条，也可能没有
            //2.2 更新原有未生效的配额
            //2.3需要把次月/年生效的这条数据，状态设置为未生效
            smsQuota.setEffectiveStatus(SmsQuotaConstant.EFFECTIVE_STATUS_WEISHENGXIAO);
            if (SmsQuotaConstant.QUOTA_TYPE_MONTH.equals(smsQuota.getQuotaType())) {
                //2.1 先更新目前有效的这条配额（主要是更新有效截止日期）
                effectiveQuota.setEffectiveEndTime(SmsQuotaDateUtils.nextMonthFirstDay());
                smsQuota.setEffectiveBeginTime(SmsQuotaDateUtils.nextMonthFirstDay());
            } else {
                effectiveQuota.setEffectiveEndTime(SmsQuotaDateUtils.nextYearFirstDay());
                smsQuota.setEffectiveBeginTime(SmsQuotaDateUtils.nextYearFirstDay());
            }
            //2.4次月生效的监控信息，在定时任务里进行处理
        }
        //更新暂时生效的数据
        effectiveQuota.setUpdateUserName(smsQuotaRequestVO.getUserName());
        effectiveQuota.setUpdateUserCode(smsQuotaRequestVO.getUserId());
        logger.info("更新暂时生效的配额：{}", effectiveQuota);
        smsQuotaRepository.update(effectiveQuota);
        //保存新的配置
        smsQuota.setCreateUserName(smsQuotaRequestVO.getUserName());
        smsQuota.setCreateUserCode(smsQuotaRequestVO.getUserId());
        smsQuota.setCreateTime(new Date());
        logger.info("处理后要保存的短信配额信息：{}", smsQuota);
        return smsQuotaRepository.insert(smsQuota);
    }

    @Override
    @PagingAnnotation
    public PageInfo<SmsQuotaResponseVO> querySmsQuotaList(SmsQuotaRequestVO smsQuotaRequestVO) {
        List<SmsQuotaResponseVO> responseVOList = smsQuotaRepository.querySmsQuotaList(smsQuotaRequestVO);
        if(CollectionUtils.isEmpty(responseVOList)){
            return new PageInfo<>();
        }
        for (SmsQuotaResponseVO vo : responseVOList) {
            this.setUsedData(vo);
            this.setRenewData(vo);
            SmsQuota smsQuota = vo.getSmsQuota();
            if (smsQuota.getQuotaPackageNum() != null) {
                vo.setQuotaCount(smsQuota.getQuota() * smsQuota.getQuotaPackageNum());
            } else {
                vo.setQuotaCount(smsQuota.getQuota());
            }
            vo.setCreateTime(smsQuota.getCreateTime());
        }

        Integer pageNum = smsQuotaRequestVO.getPageNum();
        Integer pageSize = smsQuotaRequestVO.getPageSize();

        if (responseVOList.size() <= pageSize) {
            PageInfo pageInfo = new PageInfo(responseVOList);
            pageInfo.setList(responseVOList);
            pageInfo.setTotal(responseVOList.size());
            return pageInfo;
        }
        List<SmsQuotaResponseVO> pushChannelLists2 = responseVOList.subList(pageNum * pageSize - pageSize, responseVOList.size());
        if (pushChannelLists2.size() > pageSize) {
            pushChannelLists2 = pushChannelLists2.subList(0, pageSize);
        } else {
            pushChannelLists2 = pushChannelLists2.subList(0, pushChannelLists2.size());
        }
        return new PageInfo(pushChannelLists2);
    }

    @Override
    public List<DepVo> smsQuotaDeptList(SmsQuotaRequestVO smsQuotaRequestVO) {
        List<DepVo> depVoList = new ArrayList<>();
        List<SmsQuotaResponseVO> responseVOList = smsQuotaRepository.querySmsQuotaList(smsQuotaRequestVO);
        if (CollectionUtils.isNotEmpty(responseVOList)) {
            DepVo depVo;
            for (SmsQuotaResponseVO vo : responseVOList) {
                depVo = new DepVo();
                if (StringUtils.isNotBlank(vo.getOwnerDept()) && StringUtils.isNotBlank(vo.getOwnerDeptName())) {
                    depVo.setOwnerDept(vo.getOwnerDept());
                    depVo.setOwnerDeptName(vo.getOwnerDeptName());
                    depVoList.add(depVo);
                }
            }
        }
        if (CollectionUtils.isNotEmpty(depVoList)) {
            return removeDuplicatesDep(depVoList);
        }
        return new ArrayList<>();
    }

    /**
     * 根据部门编码和部门名称去重
     *
     * @param depVoList 部门list
     * @return list
     */
    private List<DepVo> removeDuplicatesDep(List<DepVo> depVoList) {
        return depVoList.stream().collect(Collectors
                .collectingAndThen(Collectors.toCollection(() ->
                        new TreeSet<>(Comparator.comparing(dep -> dep.getOwnerDept() + "," + dep.getOwnerDeptName()))), ArrayList::new));
    }

    /**
     * 设置返回数据的 续订包数据
     *
     * @param vo vo
     */
    private void setRenewData(SmsQuotaResponseVO vo) {
        Integer renewQuota = 0;
        Integer monthRenewQuota = 0;
        SmsQuotaRenew renewQuery = new SmsQuotaRenew();
        renewQuery.setMsgSourceId(vo.getSourceCode());
        renewQuery.setStatus(1);
        List<SmsQuotaRenew> renewList = smsQuotaRenewRepository.queryRenewListByEntity(renewQuery);
        if (CollectionUtils.isNotEmpty(renewList)) {
            if (vo.getSmsQuota().getQuotaType().equals(SmsQuotaConstant.QUOTA_TYPE_YEAR)) {
                renewQuota = renewList.stream().filter(renew ->
                        StringUtils.equals(renew.getRenewYear(), SmsQuotaDateUtils.currentYear()))
                        .mapToInt(SmsQuotaRenew::getRenewQuota).sum();
                monthRenewQuota = renewList.stream().filter(renew ->
                        StringUtils.equals(renew.getRenewYear(), SmsQuotaDateUtils.currentYear())
                                && StringUtils.equals(renew.getRenewMonth(), SmsQuotaDateUtils.currentMonth()))
                        .mapToInt(SmsQuotaRenew::getRenewQuota).sum();
            } else {
                renewQuota = renewList.stream().filter(renew ->
                        StringUtils.equals(renew.getRenewYear(), SmsQuotaDateUtils.currentYear())
                                && StringUtils.equals(renew.getRenewMonth(), SmsQuotaDateUtils.currentMonth()))
                        .mapToInt(SmsQuotaRenew::getRenewQuota).sum();
                monthRenewQuota = renewQuota;
            }
        }
        vo.setRenewQuota(renewQuota);
        vo.setMonthRenewQuota(monthRenewQuota);
    }

    /**
     * 设置返回数据的已使用配额数据
     *
     * @param vo vo
     */
    private void setUsedData(SmsQuotaResponseVO vo) {
        Integer used = 0;
        Integer monthUsed = 0;
        SmsQuotaUsed usedQuery = new SmsQuotaUsed();
        usedQuery.setMsgSourceId(vo.getSourceCode());
        List<SmsQuotaUsed> usedList = smsQuotaUsedRepository.querySmsQuotaUsedByEntity(usedQuery);
        if (CollectionUtils.isNotEmpty(usedList)) {
            if (vo.getSmsQuota().getQuotaType().equals(SmsQuotaConstant.QUOTA_TYPE_YEAR)) {
                //年度
                used = usedList.stream().filter(smsQuotaUsed ->
                        StringUtils.equals(smsQuotaUsed.getUsedYear(), SmsQuotaDateUtils.currentYear()))
                        .mapToInt(SmsQuotaUsed::getUsedQuota).sum();
                monthUsed = usedList.stream().filter(smsQuotaUsed ->
                        StringUtils.equals(smsQuotaUsed.getUsedYear(), SmsQuotaDateUtils.currentYear())
                                && StringUtils.equals(smsQuotaUsed.getUsedMonth(), SmsQuotaDateUtils.currentMonth()))
                        .findAny().orElse(new SmsQuotaUsed()).getUsedQuota();
            } else {
                //月度 当前月的使用量
                used = usedList.stream().filter(smsQuotaUsed ->
                        StringUtils.equals(smsQuotaUsed.getUsedYear(), SmsQuotaDateUtils.currentYear())
                                && StringUtils.equals(smsQuotaUsed.getUsedMonth(), SmsQuotaDateUtils.currentMonth()))
                        .findAny().orElse(new SmsQuotaUsed()).getUsedQuota();
                monthUsed = used;
            }
        }
        vo.setUsedQuota(used);
        vo.setMonthUsedQuota(monthUsed);
    }

    /**
     * 比较添加的标准与已使用的配额大小
     *
     * @param smsQuota 添加的短信配额
     * @return boolean
     */
    private boolean compareAddAndUsed(SmsQuota smsQuota) {
        //判断添加的是年度，还是月度
        List<SmsQuotaUsed> usedList;
        SmsQuotaUsed query;
        if (SmsQuotaConstant.QUOTA_TYPE_YEAR.equals(smsQuota.getQuotaType())) {
            //年度
            query = new SmsQuotaUsed();
            query.setUsedYear(SmsQuotaDateUtils.currentYear());
        } else {
            //月度
            query = new SmsQuotaUsed();
            query.setUsedYear(SmsQuotaDateUtils.currentYear());
            query.setUsedMonth(SmsQuotaDateUtils.currentMonth());
        }
        query.setMsgSourceId(smsQuota.getMsgSourceId());
        logger.info("查询已使用配额的查询参数：{}", query);
        usedList = smsQuotaUsedRepository.querySmsQuotaUsedByEntity(query);
        Integer usedQuota = usedList.stream().mapToInt(SmsQuotaUsed::getUsedQuota).sum();
        logger.info("已使用的短信配额为：{}", usedQuota);
        int quotaCount;
        if (smsQuota.getQuotaPackageNum() != null) {
            quotaCount = smsQuota.getQuota() * smsQuota.getQuotaPackageNum();
        } else {
            quotaCount = smsQuota.getQuota();
        }
        if (quotaCount <= usedQuota) {
            logger.info("新设定的短信配额：{}，低于已使用的短信配额：{}", quotaCount, usedQuota);
            return false;
        }
        return true;
    }

    /**
     * 处理告警信息
     *
     * @param smsQuota       新配置的立即生效的配置
     * @param effectiveQuota 目前生效的配置
     */
    private void executeMonitorInfo(SmsQuota smsQuota, SmsQuota effectiveQuota) {
        //查询monitor是否存在告警信息
        SmsQuotaMonitor smsQuotaMonitor = smsQuotaMonitorRepository.selectMonitorByMsgSourceIdAndStatus(smsQuota.getMsgSourceId(), null);

        if (smsQuota.getMonitorMarginQuota() != null) {
            logger.info("短信配额表有告警配置");

            if (smsQuotaMonitor == null) {
                logger.info("没有查到告警配置，新增");
                SmsQuotaMonitor insert = new SmsQuotaMonitor().setMsgSourceId(smsQuota.getMsgSourceId())
                        .setMonitorQuota(smsQuota.getMonitorMarginQuota())
                        .setStatus(1)
                        .setCreateTime(new Date());
                smsQuotaMonitorRepository.insert(insert);
            } else {
                logger.info("查到告警配置，更新");
                // 新配额 > 旧配额 || 新告警值 < 旧告警值
                if (smsQuota.getQuota() > effectiveQuota.getQuota() || smsQuota.getMonitorMarginQuota() < smsQuotaMonitor.getMonitorQuota()) {
                    logger.info("更新告警状态");
                    smsQuotaMonitor.setStatus(1).setMonitorQuota(smsQuota.getMonitorMarginQuota())
                            .setUpdateTime(new Date());
                    smsQuotaMonitorRepository.update(smsQuotaMonitor);
                } else {
                    logger.info("不更新状态，但更新告警信息");
                    smsQuotaMonitor.setMonitorQuota(smsQuota.getMonitorMarginQuota())
                            .setUpdateTime(new Date());
                    smsQuotaMonitorRepository.update(smsQuotaMonitor);
                }
            }
        } else {
            logger.info("立即生效的短信配额没有设置告警配置");
            //查询是否存在告警信息
            if (smsQuotaMonitor != null) {
                logger.info("删除已存在的告警信息");
                smsQuotaMonitorRepository.delete(smsQuota.getMsgSourceId());
            }
        }
    }

    /**
     * 处理续订信息
     *
     * @param smsQuota       新配置的立即生效的配置
     * @param effectiveQuota 目前生效的配置
     */
    private void executeRenewInfo(SmsQuota smsQuota, SmsQuota effectiveQuota) {
        logger.info("处理续订信息 begin");
        //1.根据目前生效的配置，查询是否有启用的续订信息
        SmsQuotaRenew renewQuery = new SmsQuotaRenew();
        renewQuery.setStatus(1);
        renewQuery.setMsgSourceId(effectiveQuota.getMsgSourceId());

        //年转月
        if (SmsQuotaConstant.QUOTA_TYPE_MONTH.equals(smsQuota.getQuotaType()) && SmsQuotaConstant.QUOTA_TYPE_YEAR.equals(effectiveQuota.getQuotaType())) {
            logger.info("年转月");
            renewQuery.setRenewYear(SmsQuotaDateUtils.currentYear());
            List<SmsQuotaRenew> renewList = smsQuotaRenewRepository.queryRenewListByEntity(renewQuery);

            List<SmsQuotaRenew> exist = renewList.stream().filter(renew -> !renew.getRenewMonth().equals(SmsQuotaDateUtils.currentMonth()))
                    .collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(exist)){
                for(SmsQuotaRenew renew : exist){
                    renew.setStatus(2);
                    smsQuotaRenewRepository.update(renew);
                }
            }
        }
        logger.info("处理续订信息 end");
    }
}
